
package com.jf.cloud.multishop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.jf.cloud.api.auth.bo.UserInfoInTokenBO;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.auth.dto.AuthAccountDTO;
import com.jf.cloud.api.auth.feign.AccountFeignClient;
import com.jf.cloud.api.auth.vo.AuthAccountVO;
import com.jf.cloud.api.biz.feign.NotifyFeignClient;
import com.jf.cloud.api.leaf.feign.SegmentFeignClient;
import com.jf.cloud.api.rbac.dto.UserRoleDTO;
import com.jf.cloud.api.rbac.feign.UserRoleFeignClient;
import com.jf.cloud.common.constant.*;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.common.util.IpHelper;
import com.jf.cloud.multishop.dto.ShopUserDTO;
import com.jf.cloud.multishop.dto.ShopUserRegisterDTO;
import com.jf.cloud.multishop.mapper.ShopUserMapper;
import com.jf.cloud.multishop.model.ShopUser;
import com.jf.cloud.multishop.service.ShopUserService;
import com.jf.cloud.multishop.vo.ShopUserVO;
import io.seata.spring.annotation.GlobalTransactional;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zz
 * @date 2020/09/03
 */
@Service
public class ShopUserServiceImpl implements ShopUserService {

    @Resource
    private ShopUserMapper shopUserMapper;
    @Autowired
    private AccountFeignClient accountFeignClient;
    @Autowired
    private UserRoleFeignClient userRoleFeignClient;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private NotifyFeignClient notifyFeignClient;

    @Autowired
    private SegmentFeignClient segmentFeignClient;

    @Value("${jfcloud.expose.operation.auth:}")
    private Boolean permission;

    @Override
    public PageVO<ShopUserVO> pageByShopId(PageDTO pageDTO, ShopUserDTO shopUserDTO) {
        PageVO<ShopUserVO> page = PageUtil.doPage(pageDTO, () -> shopUserMapper.listByShopId(shopUserDTO));
        List<Long> userIds = page.getList().stream().map(ShopUserVO::getShopUserId).collect(Collectors.toList());
        Integer sysType = Objects.equals(shopUserDTO.getShopId(), Constant.PLATFORM_SHOP_ID) ? SysTypeEnum.PLATFORM.value() : SysTypeEnum.MULTISHOP.value();
        ServerResponseEntity<List<AuthAccountVO>> responseEntity = accountFeignClient.listUserByUserIdsAndType(userIds, sysType);
        Map<Long, AuthAccountVO> authAccountMap = responseEntity.getData().stream().collect(Collectors.toMap(AuthAccountVO::getUserId, a -> a));
        for (ShopUserVO shopUserVO : page.getList()) {
            AuthAccountVO authAccountVO = authAccountMap.get(shopUserVO.getShopUserId());
            if (Objects.isNull(authAccountVO)) {
                continue;
            }
            shopUserVO.setStatus(authAccountVO.getStatus());
            shopUserVO.setUsername(authAccountVO.getUsername());
            shopUserVO.setIsAdmin(authAccountVO.getIsAdmin());
            if (BooleanUtil.isFalse(permission) && StrUtil.isNotBlank(shopUserVO.getPhoneNum())){
                shopUserVO.setPhoneNum(PhoneUtil.hideBetween(shopUserVO.getPhoneNum()).toString());
            }
        }
        return page;
    }

    @Override
    public ShopUserVO getByUserId(Long userId) {
        ShopUserVO shopUser = shopUserMapper.getByUserId(userId);
        ServerResponseEntity<List<Long>> roleIds = userRoleFeignClient.getRoleIds(shopUser.getShopUserId());
        shopUser.setRoleIds(roleIds.getData());
        ServerResponseEntity<AuthAccountVO> accountResponse = accountFeignClient.getByUserIdAndSysType(userId, AuthUserContext.get().getSysType());
        if (!accountResponse.isSuccess()) {
            throw new LuckException(accountResponse.getMsg());
        }
        AuthAccountVO data = accountResponse.getData();
        if (Objects.nonNull(data)) {
            mapperFacade.map(data, shopUser);
        }
        return shopUser;
    }

    @Override
    public ShopUserVO getSimpleByUserId(Long userId) {
        return shopUserMapper.getByUserId(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(ShopUser shopUser, List<Long> roleIds) {
        shopUser.setShopUserId(segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_MULTISHOP_USER).getData());
        shopUserMapper.save(shopUser);
        if (CollUtil.isEmpty(roleIds)) {
            return;
        }
        UserRoleDTO userRoleDTO = new UserRoleDTO();
        userRoleDTO.setRoleIds(roleIds);
        userRoleDTO.setUserId(shopUser.getShopUserId());
        userRoleFeignClient.saveByUserIdAndSysType(userRoleDTO);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public void update(ShopUser shopUser, List<Long> roleIds) {
        UserRoleDTO userRoleDTO = new UserRoleDTO();
        userRoleDTO.setRoleIds(roleIds);
        userRoleDTO.setUserId(shopUser.getShopUserId());
        userRoleDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        shopUserMapper.update(shopUser);
        userRoleFeignClient.updateByUserIdAndSysType(userRoleDTO);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long shopUserId) {
        ServerResponseEntity<Void> responseEntity = accountFeignClient.deleteByUserIdAndSysType(shopUserId);
        if (!responseEntity.isSuccess()) {
            throw new LuckException(responseEntity.getMsg());
        }
        userRoleFeignClient.deleteByUserIdAndSysType(shopUserId);
        shopUserMapper.deleteById(shopUserId);
    }

    @Override
    public Long getUserIdByShopId(Long shopId) {
        return shopUserMapper.getUserIdByShopId(shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(ShopUserRegisterDTO shopUserRegisterDTO) {
        // 校验注册信息
        this.checkRegisterInfo(shopUserRegisterDTO);
        // 商家端用户表保存商家信息
        ShopUser shopUser = new ShopUser();
        shopUser.setShopUserId(segmentFeignClient.getSegmentId(DistributedIdKey.MALL4CLOUD_MULTISHOP_USER).getData());
        shopUser.setNickName(shopUserRegisterDTO.getUsername());
        shopUser.setPhoneNum(shopUserRegisterDTO.getMobile());
        shopUser.setHasAccount(1);
        shopUser.setShopId(Constant.DEFAULT_SHOP_ID);
        shopUserMapper.save(shopUser);
        // 账号表保存商家信息
        AuthAccountDTO authAccountDTO = new AuthAccountDTO();
        authAccountDTO.setPhone(shopUserRegisterDTO.getMobile());
        authAccountDTO.setPassword(shopUserRegisterDTO.getPassword().trim());
        authAccountDTO.setStatus(StatusEnum.ENABLE.value());
        authAccountDTO.setCreateIp(IpHelper.getIpAddr());
        authAccountDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        authAccountDTO.setUserId(shopUser.getShopUserId());
        authAccountDTO.setIsAdmin(UserAdminType.ADMIN.value());
        authAccountDTO.setTenantId(Constant.DEFAULT_SHOP_ID);
        authAccountDTO.setIsPassShop(IsPassShopEnum.NO.value());
        authAccountDTO.setUsername(shopUserRegisterDTO.getUsername());
        ServerResponseEntity<Long> saveAccountRes = accountFeignClient.save(authAccountDTO);
        if (!saveAccountRes.isSuccess()) {
            throw new LuckException(saveAccountRes.getMsg());
        }
    }

    @Override
    public ServerResponseEntity<Boolean> verifyShopUserAccount(ShopUserDTO shopUserDTO) {
        // 账号表商家信息
        AuthAccountDTO authAccountDTO = new AuthAccountDTO();
        authAccountDTO.setPhone(shopUserDTO.getPhone());
        authAccountDTO.setEmail(shopUserDTO.getEmail());
        authAccountDTO.setUsername(shopUserDTO.getUsername());
        authAccountDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        authAccountDTO.setUserId(shopUserDTO.getShopUserId());
        return accountFeignClient.verifyAccount(authAccountDTO);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public void saveAccount(ShopUserDTO shopUserDTO) {
        ShopUser shopUser = mapperFacade.map(shopUserDTO, ShopUser.class);
        shopUser.setShopUserId(null);
        shopUser.setShopId(shopUserDTO.getShopId());
        shopUser.setHasAccount(1);
        shopUser.setPhoneNum(shopUserDTO.getPhone());
        // 保存店铺职工信息
        this.save(shopUser,shopUserDTO.getRoleIds());
        Long shopUserId = shopUser.getShopUserId();
        // 账号表商家职工信息
        AuthAccountDTO authAccountDTO = new AuthAccountDTO();
        authAccountDTO.setCreateIp(IpHelper.getIpAddr());
        authAccountDTO.setPhone(shopUserDTO.getPhone());
        authAccountDTO.setEmail(shopUserDTO.getEmail());
        authAccountDTO.setUsername(shopUserDTO.getUsername());
        authAccountDTO.setSysType(AuthUserContext.get().getSysType());
        authAccountDTO.setUserId(shopUserId);
        authAccountDTO.setTenantId(shopUser.getShopId());
        authAccountDTO.setStatus(shopUserDTO.getStatus());
        authAccountDTO.setPassword(shopUserDTO.getPassword());
        authAccountDTO.setIsPassShop(IsPassShopEnum.YES.value());
        authAccountDTO.setIsAdmin(0);
        ServerResponseEntity<Long> accountResponseEntity = accountFeignClient.save(authAccountDTO);
        if (!accountResponseEntity.isSuccess()) {
            throw new LuckException(accountResponseEntity.getMsg());
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public void updateAccount(ShopUserDTO shopUserDTO) {
        // 修改店铺职工信息
        ShopUser shopUser = mapperFacade.map(shopUserDTO, ShopUser.class);
        shopUser.setPhoneNum(shopUserDTO.getPhone());
        shopUser.setHasAccount(null);
        this.update(shopUser, shopUserDTO.getRoleIds());
        AuthAccountDTO authAccountDTO = mapperFacade.map(shopUserDTO, AuthAccountDTO.class);
        UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
        authAccountDTO.setSysType(userInfoInTokenBO.getSysType());
        authAccountDTO.setTenantId(userInfoInTokenBO.getTenantId());
        authAccountDTO.setUserId(shopUserDTO.getShopUserId());
        // 修改店铺account信息
        ServerResponseEntity<Void> serverResponseEntity = accountFeignClient.update(authAccountDTO);
        if (!serverResponseEntity.isSuccess()) {
            throw new LuckException(serverResponseEntity.getMsg());
        }

    }

    @Override
    public List<ShopUserVO> listByShopId(ShopUserDTO shopUserDTO) {
        return shopUserMapper.listByShopId(shopUserDTO);
    }

    @Override
    public List<ShopUser> listShopUserByUserIds(List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        return shopUserMapper.listShopUserByUserIds(userIds);
    }

    /**
     * 校验注册信息
     * @param shopUserRegisterDTO
     * @return
     */
    public void checkRegisterInfo(ShopUserRegisterDTO shopUserRegisterDTO) {
        // 用户名
        ServerResponseEntity<Integer> usernameRes = accountFeignClient.countByUserNameAndSysType(shopUserRegisterDTO.getUsername(), SysTypeEnum.MULTISHOP.value());
        if (!usernameRes.isSuccess()) {
            throw new LuckException("服务器繁忙！");
        }
        if (usernameRes.getData() > 0) {
            throw new LuckException("用户名已经存在");
        }
        // 手机号验证码
        ServerResponseEntity<Integer> mobileRes = accountFeignClient.countByMobileAndSysType(shopUserRegisterDTO.getMobile(), SysTypeEnum.MULTISHOP.value());
        if (!mobileRes.isSuccess()) {
            throw new LuckException("服务器繁忙!");
        }
        if (mobileRes.getData() > 0) {
            throw new LuckException("该手机号已经被注册");
        }
        ServerResponseEntity<Boolean> sendNotifyResponse = notifyFeignClient.checkValidCode(shopUserRegisterDTO.getMobile(), shopUserRegisterDTO.getValidCode(), SendTypeEnum.VALID);
        Boolean data = sendNotifyResponse.getData();
        if (Objects.equals(sendNotifyResponse.getCode(), ResponseEnum.OK.value()) && Objects.nonNull(data) && !data) {
            throw new LuckException("验证码有误或已过期");
        }
    }

    @Override
    public Integer countAccoutByMobile(String mobile) {
        return shopUserMapper.countAccoutByMobile(mobile);
    }

}
